home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DJGPP / DJSRC111.ZIP / go32 / graphics.c < prev    next >
C/C++ Source or Header  |  1993-10-11  |  14KB  |  430 lines

  1. /* This is file GRAPHICS.C */
  2. /*
  3. ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  4. ** Copyright (C) 1993 Grzegorz Mazur, gbm@ii.pw.edu.pl
  5. **
  6. ** This file is distributed under the terms listed in the document
  7. ** "copying.dj", available from DJ Delorie at the address above.
  8. ** A copy of "copying.dj" should accompany this file; if not, a copy
  9. ** should be available from where this file was obtained.  This file
  10. ** may not be distributed without a verbatim copy of "copying.dj".
  11. **
  12. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  13. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. */
  15.  
  16. #pragma inline
  17.  
  18. /* History:42,23 */
  19. #include <dos.h>
  20. #include <fcntl.h>
  21. #include <sys/stat.h>
  22. #include <stdio.h>
  23. #include <alloc.h>
  24. #include <string.h>
  25. #include <io.h>
  26.  
  27. #include "gotypes.h"
  28. #include "paging.h"
  29. #include "graphics.h"
  30. #include "tss.h"
  31. #include "gdt.h"
  32. #include "grdriver.h"
  33.  
  34. extern fillgdt(int sel, word32 limit, word32 base, word8 type, int G);
  35.  
  36. /* DJ - tcc 2.0 can't handle far arrays */
  37. /* extern char far builtin_driver_code[]; */
  38. extern char builtin_driver_code[];
  39. /* DJ - end */
  40.  
  41. extern int  builtin_driver_size;
  42.  
  43. /* driver version defs */
  44. #define BAD    (-2)            /* tried loading -- driver reports error */
  45. #define UNK    (-1)            /* unknown -- no graphics call made yet */
  46. #define GRD    0            /* DJ's original 256 color driver */
  47. #define GRN    1            /* GRX 1.01+ programmable color driver */
  48. #define VDR    2            /* GRX 1.03+ VESA compatible extended driver */
  49.  
  50. /* driver stuff */
  51. static GrDriverHeader far *driver = NULL;
  52. static char *drv_name = NULL;
  53. static char  drv_version = UNK;
  54.  
  55. /* driver default parameters filled out from GO32 env. var. */
  56. int gr_def_tw = 0;
  57. int gr_def_th = 0;
  58. int gr_def_gw = 0;
  59. int gr_def_gh = 0;
  60. int gr_def_numcolor = 0;
  61.  
  62. /* Direct INT 10h function calls with AX >= this value to the 'graphics_assist' function */
  63. /* One of the 'graphics_assist' functions can be used to reset this to 0xff00 */
  64. /* Older versions of GRX used INT 10h, AH=0FEh to get the driver mode parameters. */
  65. /* GRX 1.03+ does not use this call any more. Desqview also seems to be using the */
  66. /* INT 10h, AH=0FEh call. By allowing to reset this value to 0xff00, GO32 will support */
  67. /* both. Later when GRX 1.03 and later versions will be more out for some time we can */
  68. /* change the default... */
  69. word16 gr_assist_func_start = 0xfe00;
  70.  
  71. /* two graphics page tables */
  72. word32 far *graphics_pt1 = NULL;
  73. word32 far *graphics_pt2 = NULL;
  74. word32 graphics_pt1_lin;
  75. word32 graphics_pt2_lin;
  76.  
  77. /* pointers necessary for moving the graphics page tables in the page directory */
  78. /* they point to the start of the graphics region in the PD-s */
  79. word32 far *graphics_pd;
  80. word8  far *graphics_pd_seg;
  81. word32 graphics_pd_lin;
  82. word32 graphics_pd_seg_lin;
  83.  
  84. /* current location of the two page tables */
  85. word16 graphics_pt1_loc;
  86. word16 graphics_pt2_loc;
  87.  
  88. /* the protected mode paging function */
  89. word32 gr_paging_func;
  90.  
  91. /* linear pointers to prepared page table segments */
  92. word32 gr_rw_table_lin;
  93. word32 gr_ro_table_lin;
  94. word32 gr_wo_table_lin;
  95.  
  96. /* other parameters for protected mode paging routine */
  97. word32 gr_sgl_page_size  = 16;        /* R/W page size in 4kByte units */
  98. word32 gr_r_w_page_size  = 16;        /* split page sizes in 4kByte units */
  99. word8  gr_sgl_page_shift = 4;        /* log2 of the R/W page size in 4kByte units */
  100. word8  gr_r_w_page_shift = 4;        /* log2 of the split page sizes in 4kByte units */
  101. word8  gr_rw_page_offset = 0;        /* diff between two windows in R/W mode (ATI!) */
  102.  
  103. /* prepared page table segments: */
  104. /* paging code can use rep movsl-s instead of fiddling with bits */
  105. /* allocate enough space for 128kByte graphics map */
  106. /* also contains the real mode paging parameter transfer buffer */
  107.  
  108. /* DJ - tcc 2.0 can't do far arrays */
  109. /* static word32 far  gr_prepared_tables[3*(128/4) + 4 + 1]; */
  110. static word32 gr_prepared_tables[3*(128/4) + 4 + 1];
  111. /* DJ - end */
  112.  
  113. static word32 far *gr_rw_table;
  114. static word32 far *gr_ro_table;
  115. static word32 far *gr_wo_table;
  116.  
  117. /* stuff for the real-mode paging function interface */
  118. word32 real_paging_buffer_lin;        /* linear address of param passing buffer */
  119. word32 real_paging_buffer_virt;        /* virtual address of param passing buffer */
  120. word32 real_paging_func_virt;        /* virtual address of the arena paging function */
  121.  
  122. extern void far real_paging_routine(void);
  123. extern void far arena_real_paging_func(void);
  124.  
  125. static void far dummy_paging_routine(void)
  126. {
  127.     return;
  128. }
  129.  
  130. static void fbzero(void far *addr,int size)
  131. {
  132.     asm les  di,dword ptr addr;
  133.     asm mov  cx,word  ptr size;
  134.     asm shr  cx,1;
  135.     asm je     done;
  136.     asm xor  ax,ax;
  137.     asm rep  stosw;
  138.       done:
  139.     return;
  140. }
  141.  
  142. static void setup_paging_routine(void)
  143. {
  144.     word16 gr_seg  = (drv_version <= UNK) ? FP_SEG(dummy_paging_routine) : FP_SEG(driver);
  145.     word16 gr_off  = (drv_version <= UNK) ? FP_OFF(dummy_paging_routine) : driver->paging_routine;
  146.     word32 rw_addr = 0x000a0000L;
  147.     word32 ro_addr = 0x000a0000L;
  148.     word32 wo_addr = 0x000a0000L;
  149.     int i;
  150.  
  151.     if(drv_version == VDR) {
  152.         rw_addr = wo_addr = (word32)driver->wr_page_start << 4;
  153.         ro_addr = (driver->rd_page_start == 0xffff) ?
  154.             rw_addr :
  155.             (word32)driver->rd_page_start << 4;
  156.         gr_sgl_page_shift = gr_r_w_page_shift = driver->page_size_shift;
  157.         gr_rw_page_offset = 0;
  158.         if(ro_addr > wo_addr) {
  159.         /* ATI style paging: two split READ/WRITE 32kByte pages */
  160.         /* it is handled by mapping the two pages continguously in R/W mode to */
  161.         /* form a single 64K page. In separate R and W mode we have two */
  162.         /* 32 kByte pages. For this we need an offset of one between the two */
  163.         /* page indices in R/W mode */
  164.         gr_sgl_page_shift++;
  165.         gr_rw_page_offset = 1;
  166.         }
  167.         gr_sgl_page_size = 1 << gr_sgl_page_shift;
  168.         gr_r_w_page_size = 1 << gr_r_w_page_shift;
  169.         if(driver->driver_options & GRD_PROTECTED_PAGING) {
  170.         if(driver->VESA_paging_fnc != 0L) {
  171.             fillgdt(g_VESAfunc, 0xffff,
  172.             (word32)FP_SEG(driver->VESA_paging_fnc) * 16L,
  173.             0x9a, 0
  174.             );
  175.             driver->VESA_paging_fnc = MK_FP(
  176.             (g_VESAfunc << 3),
  177.             FP_OFF(driver->VESA_paging_fnc)
  178.             );
  179.         }
  180.         }
  181.         else {
  182.         gr_seg = FP_SEG(real_paging_routine);
  183.         gr_off = FP_OFF(real_paging_routine);
  184.         }
  185.     }
  186.     fillgdt(g_grdr, 0xffff, (word32)gr_seg << 4, 0x9a, 0);
  187.     gr_paging_func = (word32)MK_FP((g_grdr << 3),gr_off);
  188.     fbzero(gr_prepared_tables,sizeof(gr_prepared_tables));
  189.     if(graphics_pt1) {
  190.         fbzero(graphics_pt1,4096);
  191.         fbzero(graphics_pt2,4096);
  192.     }
  193.     for(i = 0; i < (int)gr_sgl_page_size; i++) {
  194.         gr_rw_table[i] = rw_addr | (PT_W | PT_U | PT_P);
  195.         rw_addr += 4096;
  196.     }
  197.     for(i = 0; i < (int)gr_r_w_page_size; i++) {
  198.         gr_wo_table[i] = wo_addr | (PT_W | PT_U | PT_P);
  199.         gr_ro_table[i] = ro_addr | (PT_U | PT_P);
  200.         wo_addr += 4096;
  201.         ro_addr += 4096;
  202.     }
  203. }
  204.  
  205. void setup_graphics_driver(char *name)
  206. {
  207.     word32 far *real_paging_buf;
  208.  
  209.     if(name != NULL) drv_name = strdup(name);
  210.     gr_rw_table = MK_FP(FP_SEG(gr_prepared_tables),((FP_OFF(gr_prepared_tables) + 3) & ~3));
  211.     gr_ro_table = gr_rw_table + 128/4;
  212.     gr_wo_table = gr_ro_table + 128/4;
  213.     gr_rw_table_lin = ptr2linear(gr_rw_table);
  214.     gr_ro_table_lin = ptr2linear(gr_ro_table);
  215.     gr_wo_table_lin = ptr2linear(gr_wo_table);
  216.     real_paging_buf = gr_wo_table + 128/4;
  217.     real_paging_buffer_lin  = ptr2linear(real_paging_buf);
  218.     real_paging_buffer_virt = real_paging_buffer_lin + 0xe0000000L;
  219.     real_paging_func_virt    = ptr2linear(arena_real_paging_func) + 0xe0000000L;
  220.     setup_paging_routine();
  221. }
  222.  
  223. static void load_graphics_driver(void)
  224. {
  225.     int  far (*init_func)(void);
  226.     char *try,*opt = NULL;
  227.     char far *p1,far *p2;
  228.     FILE *drvfile;
  229.     int  size,ch;
  230.  
  231.     if(drv_version != UNK) return;
  232.     if(drv_name) {
  233.         for(try = drv_name; (try = strchr(try,':')) != NULL; try++) {
  234.         if(try[1] == ':') {
  235.             opt = &try[2];
  236.             *try = '\0';
  237.             break;
  238.         }
  239.         }
  240.         if((*drv_name != '\0') && ((drvfile = fopen(drv_name,"rb")) != NULL)) {
  241.         try  = NULL;
  242.         size = (int)filelength(fileno(drvfile));
  243.         if((size >= 100) && ((size <= builtin_driver_size) || ((try = malloc(size + 16)) != NULL))) {
  244.             p1 = (size <= builtin_driver_size) ? builtin_driver_code : (char far *)try;
  245.             p1 = MK_FP((FP_SEG(p1) + ((FP_OFF(p1) + 15) >> 4)),0);
  246.             driver = (GrDriverHeader far *)p1;
  247.             while(--size >= 0) {
  248.             if((ch = fgetc(drvfile)) == EOF) {
  249.                 /* bad driver file, disk error, etc..? */
  250.                 if(try || (p1 == (char *)driver)) {
  251.                 /* fortunately we still have the original */
  252.                 if(try) free(try);
  253.                 driver = NULL;
  254.                 }
  255.                 else {
  256.                 /* no help, even the built-in driver is screwed up now */
  257.                 drv_version = BAD;
  258.                 }
  259.                 break;
  260.             }
  261.             *p1++ = ch;
  262.             }
  263.         }
  264.         fclose(drvfile);
  265.         }
  266.     }
  267.     if(drv_version != BAD) {
  268.         drv_version = GRD;
  269.         if(!driver) {
  270.         driver = MK_FP((FP_SEG(builtin_driver_code) + ((FP_OFF(builtin_driver_code) + 15) >> 4)),0);
  271.         if(FP_OFF(builtin_driver_code) & 15) {
  272.             size = builtin_driver_size;
  273.             p1 = (char far *)driver + size;
  274.             p2 = builtin_driver_code + size;
  275.             while(--size >= 0) *(--p1) = *(--p2);
  276.         }
  277.         }
  278.         if(driver->driver_flags & GRD_NEW_DRIVER) {
  279.         p1 = (char far *)driver->vdr_magic;
  280.         p2 = ".VDR driver";
  281.         while(*p1 && (*p1 == *p2)) p1++,p2++;
  282.         drv_version = (*p1 == *p2) ? VDR : GRN;
  283.         if((drv_version == VDR) && opt) while(*opt != '\0') {
  284.             switch(*opt) {
  285.               case 'P':
  286.               case 'p':
  287.             driver->driver_options |= GRD_PROTECTED_PAGING;
  288.             break;
  289.               case 'F':
  290.               case 'f':
  291.             driver->driver_options |= GRD_FAST_256_MODE;
  292.             break;
  293.               case '5':
  294.             driver->driver_options |= GRD_15_PLANE_MODE;
  295.             break;
  296.             }
  297.             opt++;
  298.         }
  299.         init_func = MK_FP(FP_SEG(driver),driver->driver_init_routine);
  300.         _AX = FP_SEG(driver);
  301.         asm push ds;
  302.         asm mov  ds,ax;
  303.         asm call dword ptr ss:[init_func];
  304.         asm pop  ds;
  305.         if(_AX == 0) {
  306.             /* You may want to do something more appropriate here */
  307.             fputs("Graphics initialization error -- probably incorrect driver\n",stderr);
  308.             drv_version = BAD;
  309.         }
  310.         }
  311.         switch(drv_version) {
  312.           case VDR:
  313.           case GRN:
  314.         if(gr_def_numcolor > 0) driver->def_numcolor = gr_def_numcolor;
  315.           case GRD:
  316.         if(gr_def_tw > 0) driver->def_tw = gr_def_tw;
  317.         if(gr_def_th > 0) driver->def_th = gr_def_th;
  318.         if(gr_def_gw > 0) driver->def_gw = gr_def_gw;
  319.         if(gr_def_gh > 0) driver->def_gh = gr_def_gh;
  320.         }
  321.     }
  322.     if(drv_name) free(drv_name);
  323.     setup_paging_routine();
  324. }
  325.  
  326. static word32 add_driver_version(word16 flags)
  327. {
  328.     switch(drv_version) {
  329.         case GRD: return(flags | GR_DRV_VER_GRD);
  330.         case GRN: return(flags | GR_DRV_VER_GRN);
  331.         case VDR: return(flags | GR_DRV_VER_VDR);
  332.         default:  return(-1L);
  333.     }
  334. }
  335.  
  336. void graphics_assist(void)
  337. {
  338.     void far (*driver_func)(void);
  339.     word16 mode,cnum,cols,rows;
  340.  
  341.     switch((word16)tss_ptr->tss_eax & 0xff00) {
  342.       case 0xff00:                    /* graphics assist function */
  343.         switch(mode = ((word16)tss_ptr->tss_eax & 0x00ff)) {
  344.           case 0x00ff:                /* SUB-FNC 0xFF: make GO32 Desqview compatible */
  345.         gr_assist_func_start = 0xff00;
  346.         break;
  347.           case 0x00fe:                /* SUB-FNC 0xFE: return driver header adr */
  348.         if(drv_version == UNK) load_graphics_driver();
  349.         /* don't add 0xe0000000 -- GRX will figure whether running under DPMI or VCPI */
  350.         tss_ptr->tss_eax = (drv_version == BAD) ? 0L : (word32)ptr2linear(driver);
  351.         break;
  352.           case 0x00fd:                /* SUB-FNC 0xFD: call pg fnc in real mode */
  353.         if(drv_version < GRD) break;
  354.         driver_func = MK_FP(FP_SEG(driver),driver->paging_routine);
  355.         _AX = (word16)tss_ptr->tss_ebx;
  356.         asm push si;
  357.         asm push di;
  358.         asm call dword ptr ss:[driver_func];
  359.         asm pop  di;
  360.         asm pop  si;
  361.         break;
  362.           case 0x00fc:                /* SUB-FNC 0xFC: set virtual screen start */
  363.         if(drv_version != VDR) break;
  364.         cols = (word16)tss_ptr->tss_ecx;
  365.         rows = (word16)tss_ptr->tss_edx;
  366.         driver_func = MK_FP(FP_SEG(driver),driver->set_screen_start);
  367.         _AX  = FP_SEG(driver);
  368.         asm mov  cx,word ptr cols;
  369.         asm mov  dx,word ptr rows;
  370.         asm push ds;
  371.         asm mov  ds,ax;
  372.         asm call dword ptr ss:[driver_func];
  373.         asm pop  ds;
  374.         break;
  375.           default:                    /* mode set */
  376.         if(drv_version == UNK) load_graphics_driver();
  377.         switch(drv_version) {
  378.           case GRD:
  379.             if(mode > 8) mode = 8;
  380.           case GRN:
  381.             if(mode > 9) mode = 9;
  382.           case VDR:
  383.             if((mode & 0x7f) > 10) mode = (mode & 0x80) + 10;
  384.             cnum = (word16)tss_ptr->tss_ebx;
  385.             cols = (word16)tss_ptr->tss_ecx;
  386.             rows = (word16)tss_ptr->tss_edx;
  387.             driver_func = MK_FP(FP_SEG(driver),driver->modeset_routine);
  388.             _AX  = FP_SEG(driver);
  389.             asm push ds;
  390.             asm push ax;
  391.             asm mov  ax,word ptr mode;
  392.             asm mov  bx,word ptr cnum;
  393.             asm mov  cx,word ptr cols;
  394.             asm mov  dx,word ptr rows;
  395.             asm pop  ds;
  396.             asm call dword ptr ss:[driver_func];
  397.             asm pop  ds;
  398.             asm mov  word ptr cnum,bx;
  399.             asm mov  word ptr cols,cx;
  400.             asm mov  word ptr rows,dx;
  401.             tss_ptr->tss_ebx = add_driver_version(cnum);
  402.             tss_ptr->tss_ecx = (word32)cols;
  403.             tss_ptr->tss_edx = (word32)rows;
  404.             setup_paging_routine();
  405.             break;
  406.           default:
  407.             /* BAD driver -- only perform text mode sets */
  408.             if(mode < 4) {
  409.             _AX = 3;
  410.             geninterrupt(0x10);
  411.             tss_ptr->tss_ebx = 0;
  412.             tss_ptr->tss_ecx = 80;
  413.             tss_ptr->tss_edx = 25;
  414.             break;
  415.             }
  416.             tss_ptr->tss_ebx = (-1);        /* signal error */
  417.             break;
  418.         }
  419.         }
  420.         break;
  421.       case 0xfe00:                    /* old style driver mode info */
  422.         if(drv_version == UNK) load_graphics_driver();
  423.         tss_ptr->tss_ebx = (drv_version < GRD) ? -1L : add_driver_version(driver->driver_flags);
  424.         tss_ptr->tss_ecx = (drv_version < GRN) ?  0L : 0xe0000000L + ptr2linear(MK_FP(FP_SEG(driver),driver->text_table));
  425.         tss_ptr->tss_edx = (drv_version < GRN) ?  0L : 0xe0000000L + ptr2linear(MK_FP(FP_SEG(driver),driver->graphics_table));
  426.         break;
  427.     }
  428. }
  429.  
  430.